// Copyright(c) 2011 Matthew McMullan, Jorel Lalicki and Mike Heise, Jorel Lalicki and Mike Heise. See copying.txt for details.

#ifndef __agml_complex_h__
#define __agml_complex_h__

// make sure that this file is never included directly
#ifndef __agml_agml_h__
#error "Include AGML from agml.h only. This file is not a valid entry point for the library."
#endif

namespace agml {

namespace complex_datatypes {
	template<typename t> struct x {
		t r;
		t i;
		x(): r(0), i(0) {};
		x(t R): r(R), i(0) {};
		x(t R, t I): r(R), i(I) {};
		x(const x &o): r(o.r), i(o.i) {};
		x& operator=(const x &o) {
			r = o.r; i = o.i;
			return *this;
		}
		x& operator=(const t &o) {
			r = o; i = t();
			return *this;
		}
		super_inline bool operator==(const x &o) const {
			return o.r==r&&o.i==i;
		}
		super_inline bool operator!=(const x &o) const {
			return o.r!=r||o.i!=i;
		}
		super_inline bool operator<(const x &o) const {
			return (r*r+i*i)<(o.r*o.r+o.i*o.i);
		}
		super_inline bool operator<=(const x &o) const {
			return (r*r+i*i)<=(o.r*o.r+o.i*o.i);
		}
		super_inline bool operator>(const x &o) const {
			return (r*r+i*i)>(o.r*o.r+o.i*o.i);
		}
		super_inline bool operator>=(const x &o) const {
			return (r*r+i*i)>=(o.r*o.r+o.i*o.i);
		}
		super_inline x& operator+=(const x &o) {
			r+=o.r;
			i+=o.i;
			return *this;
		}
		super_inline x operator+(const x &o) const {
			x tmp;
			tmp.r = r+o.r;
			tmp.r = i+o.i;
			return tmp;
		}
		super_inline x& operator+=(const t &o) {
			r+=o;
			return *this;
		}
		super_inline x operator+(const t &o) const {
			x tmp;
			tmp.r = r+o;
			tmp.r = i;
			return tmp;
		}
		super_inline x& operator-=(const x &o) {
			r-=o.r;
			i-=o.i;
			return *this;
		}
		super_inline x operator-(const x &o) const {
			x tmp;
			tmp.r = r-o.r;
			tmp.i = i-o.i;
			return tmp;
		}
		super_inline x& operator-=(const t &o) {
			r-=o;
			return *this;
		}
		super_inline x operator-(const t &o) const {
			x tmp;
			tmp.r = r-o;
			tmp.r = i;
			return tmp;
		}
		super_inline x& operator*=(const x &o) {
			t tmp = r*o.r - i*o.i;
			i = r*o.i+o.r*i;
			r = tmp;
			return *this;
		}
		super_inline x operator*(const x &o) const {
			x tmp;
			tmp.r = r*o.r - i*o.i;
			tmp.i = r*o.i+o.r*i;
			return tmp;
		}
		super_inline x& operator*=(const t &o) {
			i = i*o;
			r = r*o;
			return *this;
		}
		super_inline x operator*(const t &o) const {
			x tmp;
			tmp.r = r*o;
			tmp.i = i*o;
			return tmp;
		}
		super_inline x& operator/=(const x &o) {
			t a, b, c;
			a = r*o.r + i*o.i;
			b = o.r*i + r*o.i;
			c = o.r*o.r + o.i*o.i;
			r = a/c;
			i = b/c;
			return *this;
		}
		super_inline x operator/(const x &o) const {
			t a, b, c;
			x tmp;
			a = r*o.r + i*o.i;
			b = o.r*i + r*o.i;
			c = o.r*o.r + o.i*o.i;
			tmp.r = a/c;
			tmp.i = b/c;
			return tmp;
		}
		super_inline x& operator/=(const t &o) {
			r /= o;
			i /= o;
			return *this;
		}
		super_inline x operator/(const t &o) const {
			x tmp;
			tmp.r = r/o;
			tmp.i = i/o;
			return tmp;
		}
		super_inline x& operator%=(const x &o) {
			t a, b, c;
			a = r*o.r + i*o.i;
			b = o.r*i + r*o.i;
			c = o.r*o.r + o.i*o.i;
			r = a%c;
			i = b%c;
			return *this;
		}
		super_inline x operator%(const x &o) const {
			t a, b, c;
			x tmp;
			a = r*o.r + i*o.i;
			b = o.r*i + r*o.i;
			c = o.r*o.r + o.i*o.i;
			tmp.r = a%c;
			tmp.i = b%c;
			return tmp;
		}
		super_inline x& operator%=(const t &o) {
			r %= o;
			i %= o;
			return *this;
		}
		super_inline x operator%(const t &o) const {
			x tmp;
			tmp.r = r%o;
			tmp.i = i%o;
			return tmp;
		}
	};
}
using namespace complex_datatypes;
typedef x<i8> xi8;
typedef x<u8> xu8;
typedef x<i16> xi16;
typedef x<u16> xu16;
typedef x<i32> xi32;
typedef x<u32> xu32;
typedef x<f32> xf32;
typedef x<i64> xi64;
typedef x<u64> xu64;
typedef x<f64> xf64;
typedef x<f80> xf80;

typedef const xu8 Cxu8;
typedef const xu16 Cxu16;
typedef const xu32 Cxu32;
typedef const xu64 Cxu64;
typedef const xi8 Cxi8;
typedef const xi16 Cxi16;
typedef const xi32 Cxi32;
typedef const xi64 Cxi64;
typedef const xf32 Cxf32;
typedef const xf64 Cxf64;
typedef const xf80 Cxf80;

}

#endif
